﻿using System;
using System.Data;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
using FBroSharp;
using FBroSharp.Lib;
using FBroSharp.Value;
using FBroSharp.Event;
using FBroSharp.DataType;
using FBroSharp.Callback;
using FBroSharp.Const;
using OfficeOpenXml; // 需要安装 EPPlus NuGet 包

namespace _4_表单批量填写器
{
    public partial class Form1 : Form
    {
        private IFBroSharpBrowser browser;
        private string targetUrl = "https://httpbin.org/forms/post";
        private const string BROWSER_USER_FLAG = "main_browser";
        
        public Form1()
        {
            InitializeComponent();
            // 设置 EPPlus 许可证（非商业用途）
            ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
        }

        /// <summary>
        /// 创建浏览器实例
        /// </summary>
        private async Task CreateBrowserAsync()
        {
            try
            {
                // 创建窗口信息
                FBroSharpWindowsInfo windows_info = new FBroSharpWindowsInfo
                {
                    parent_window = IntPtr.Zero,
                    x = 0,
                    y = 0,
                    width = 1280,
                    height = 800,
                    window_name = "表单填写器"
                };

                // 创建浏览器事件回调类
                BrowserEvent browser_event = new BrowserEvent();

                // 创建浏览器
                if (FBroSharpControl.CreatBrowser(
                    targetUrl,
                    windows_info,
                    default,
                    default,
                    default,
                    browser_event,
                    default,
                    BROWSER_USER_FLAG))
                {
                    Console.WriteLine("浏览器创建成功");
                    
                    // 等待浏览器创建完成并获取实例
                    await Task.Delay(2000); // 等待浏览器初始化完成
                    browser = FBroSharpBrowserListControl.GetBrowserFromFlag(BROWSER_USER_FLAG);
                    
                    if (browser == null || !browser.IsValid)
                    {
                        MessageBox.Show("浏览器创建失败", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                    
                    MessageBox.Show("浏览器创建成功！", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else
                {
                    MessageBox.Show("浏览器创建失败", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"创建浏览器失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// 测试浏览器中的表单填写功能
        /// </summary>
        private async Task TestFormFillingAsync(IFBroSharpBrowser browser)
        {
            try
            {
                Console.WriteLine("开始测试表单填写功能...");
                
                // 测试填写客户姓名
                var result1 = await FillInputAsync(browser, "input[name='custname']", "测试用户");
                Console.WriteLine($"填写客户姓名结果: {result1}");
                
                // 验证填写结果
                string verificationJs = @"
                    (function() {
                        var element = document.querySelector(""input[name='custname']"");
                        return element ? element.value : 'not found';
                    })();
                ";
                
                var verificationResult = await ExecuteJavaScriptAsync(browser, verificationJs);
                Console.WriteLine($"验证结果: {verificationResult}");
                
                // 测试填写电话
                var result2 = await FillInputAsync(browser, "input[name='custtel']", "13800138000");
                Console.WriteLine($"填写电话结果: {result2}");
                
                // 测试选择披萨尺寸
                var result3 = await CheckCheckboxAsync(browser, "input[name='size'][value='large']", true);
                Console.WriteLine($"选择披萨尺寸结果: {result3}");
                
                Console.WriteLine("表单填写测试完成");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"测试表单填写功能时出错: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// 单条数据填写（测试用）
        /// </summary>
        private async void btnFillSingle_Click(object sender, EventArgs e)
        {
            if (browser == null || !browser.IsValid)
            {
                // 尝试重新获取浏览器实例
                browser = FBroSharpBrowserListControl.GetBrowserFromFlag(BROWSER_USER_FLAG);
                if (browser == null || !browser.IsValid)
                {
                    MessageBox.Show("请先初始化浏览器", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
            }
            
            try
            {
                // 先运行测试
                await TestFormFillingAsync(browser);
                
                // 然后填写实际表单
                await FillFormAsync(browser, null);
                MessageBox.Show("表单填写完成！", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"填写失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// 批量填写（从 Excel 读取）
        /// </summary>
        private async void btnFillBatch_Click(object sender, EventArgs e)
        {
            if (browser == null || !browser.IsValid)
            {
                // 尝试重新获取浏览器实例
                browser = FBroSharpBrowserListControl.GetBrowserFromFlag(BROWSER_USER_FLAG);
                if (browser == null || !browser.IsValid)
                {
                    MessageBox.Show("请先初始化浏览器", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
            }
            
            // 选择 Excel 文件
            using (var openFileDialog = new OpenFileDialog())
            {
                openFileDialog.Filter = "Excel Files|*.xlsx;*.xls|CSV Files|*.csv";
                openFileDialog.Title = "选择包含表单数据的 Excel 或 CSV 文件";
                
                if (openFileDialog.ShowDialog() != DialogResult.OK)
                    return;
                
                try
                {
                    DataTable dataTable;
                    if (openFileDialog.FileName.EndsWith(".csv", StringComparison.OrdinalIgnoreCase))
                    {
                        dataTable = ReadCsvFile(openFileDialog.FileName);
                    }
                    else
                    {
                        dataTable = ReadExcelFile(openFileDialog.FileName);
                    }
                    
                    if (dataTable == null || dataTable.Rows.Count == 0)
                    {
                        MessageBox.Show("文件为空或格式错误", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                    
                    int successCount = 0;
                    int failCount = 0;
                    
                    foreach (DataRow row in dataTable.Rows)
                    {
                        try
                        {
                            await FillFormAsync(browser, row);
                            successCount++;
                            await Task.Delay(1000); // 每条数据之间延迟1秒
                        }
                        catch (Exception ex)
                        {
                            failCount++;
                            Console.WriteLine($"填写失败: {ex.Message}");
                        }
                    }
                    
                    MessageBox.Show($"批量填写完成！\n成功: {successCount} 条\n失败: {failCount} 条", 
                        "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"批量填写失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        /// <summary>
        /// 填写表单（核心方法）
        /// </summary>
        private async Task FillFormAsync(IFBroSharpBrowser browser, DataRow row)
        {
            if (!browser.IsValid)
                throw new Exception("浏览器实例无效");
            
            try
            {
                // 填写客户姓名
                string custname = row?["custname"]?.ToString() ?? "张三";
                var result1 = await FillInputAsync(browser, "input[name='custname']", custname);
                Console.WriteLine($"填写客户姓名结果: {result1}");
                
                // 填写电话
                string custtel = row?["custtel"]?.ToString() ?? "13800138000";
                var result2 = await FillInputAsync(browser, "input[name='custtel']", custtel);
                Console.WriteLine($"填写电话结果: {result2}");
                
                // 填写邮箱
                string custemail = row?["custemail"]?.ToString() ?? "zhangsan@example.com";
                var result3 = await FillInputAsync(browser, "input[name='custemail']", custemail);
                Console.WriteLine($"填写邮箱结果: {result3}");
                
                // 选择披萨尺寸（单选框）
                string size = row?["size"]?.ToString() ?? "medium";
                var result4 = await CheckCheckboxAsync(browser, $"input[name='size'][value='{size}']", true);
                Console.WriteLine($"选择披萨尺寸结果: {result4}");
                
                // 选择配料（复选框）
                string[] toppings = row?["topping"]?.ToString().Split(',') ?? new string[] { "bacon", "cheese" };
                // 先取消所有选择
                await CheckCheckboxAsync(browser, "input[name='topping'][value='bacon']", false);
                await CheckCheckboxAsync(browser, "input[name='topping'][value='cheese']", false);
                await CheckCheckboxAsync(browser, "input[name='topping'][value='onion']", false);
                await CheckCheckboxAsync(browser, "input[name='topping'][value='mushroom']", false);
                
                // 再选择需要的配料
                foreach (string topping in toppings)
                {
                    var result5 = await CheckCheckboxAsync(browser, $"input[name='topping'][value='{topping.Trim()}']", true);
                    Console.WriteLine($"选择配料 {topping} 结果: {result5}");
                }
                
                // 填写配送时间
                string delivery = row?["delivery"]?.ToString() ?? "12:00";
                var result6 = await FillInputAsync(browser, "input[name='delivery']", delivery);
                Console.WriteLine($"填写配送时间结果: {result6}");
                
                // 填写配送说明
                string comments = row?["comments"]?.ToString() ?? "请尽快配送";
                var result7 = await FillInputAsync(browser, "textarea[name='comments']", comments);
                Console.WriteLine($"填写配送说明结果: {result7}");
                
                // 等待一段时间确保所有操作完成
                await Task.Delay(500);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"填写表单时出错: {ex.Message}");
                throw;
            }
        }

        /// <summary>
        /// 填写输入框
        /// </summary>
        private async Task<string> FillInputAsync(IFBroSharpBrowser browser, string selector, string value)
        {
            // 使用双引号而不是单引号来避免转义问题
            var jsCode = $@"
                (function() {{
                    var element = document.querySelector(""{selector}"");
                    if (element) {{
                        element.value = ""{value.Replace("\"", "\\\"")}"";
                        element.dispatchEvent(new Event('input', {{ bubbles: true }}));
                        element.dispatchEvent(new Event('change', {{ bubbles: true }}));
                        return 'success';
                    }}
                    return 'element not found';
                }})();
            ";
            
            var result = await ExecuteJavaScriptAsync(browser, jsCode);
            await Task.Delay(100);
            return result ?? "no result";
        }

        /// <summary>
        /// 选择下拉框选项
        /// </summary>
        private async Task<string> SelectOptionAsync(IFBroSharpBrowser browser, string selector, string value)
        {
            var jsCode = $@"
                (function() {{
                    var select = document.querySelector(""{selector}"");
                    if (!select) return 'select not found';
                    
                    // 尝试通过 value 匹配
                    var option = Array.from(select.options).find(opt => opt.value === ""{value.Replace("\"", "\\\"")}"");
                    
                    // 如果没找到，尝试通过 text 匹配
                    if (!option) {{
                        option = Array.from(select.options).find(opt => opt.text === ""{value.Replace("\"", "\\\"")}"");
                    }}
                    
                    if (option) {{
                        select.value = option.value;
                        select.dispatchEvent(new Event('change', {{ bubbles: true }}));
                        return 'success';
                    }}
                    
                    return 'option not found';
                }})();
            ";
            
            var result = await ExecuteJavaScriptAsync(browser, jsCode);
            await Task.Delay(100);
            return result ?? "no result";
        }

        /// <summary>
        /// 勾选/取消勾选复选框或单选框
        /// </summary>
        private async Task<string> CheckCheckboxAsync(IFBroSharpBrowser browser, string selector, bool check)
        {
            var jsCode = $@"
                (function() {{
                    var element = document.querySelector(""{selector}"");
                    if (element) {{
                        element.checked = {(check ? "true" : "false")};
                        element.dispatchEvent(new Event('change', {{ bubbles: true }}));
                        return 'success';
                    }}
                    return 'element not found';
                }})();
            ";
            
            var result = await ExecuteJavaScriptAsync(browser, jsCode);
            await Task.Delay(100);
            return result ?? "no result";
        }

        /// <summary>
        /// 点击提交按钮
        /// </summary>
        private async Task<string> ClickSubmitAsync(IFBroSharpBrowser browser, string selector)
        {
            var jsCode = $@"
                (function() {{
                    var button = document.querySelector(""{selector}"");
                    if (button) {{
                        button.click();
                        return 'success';
                    }}
                    return 'button not found';
                }})();
            ";
            
            var result = await ExecuteJavaScriptAsync(browser, jsCode);
            return result ?? "no result";
        }

        /// <summary>
        /// 执行 JavaScript 代码
        /// </summary>
        private async Task<string> ExecuteJavaScriptAsync(IFBroSharpBrowser browser, string jsCode)
        {
            try
            {
                var frame = browser.GetMainFrame();
                if (frame == null)
                {
                    Console.WriteLine("无法获取主框架");
                    throw new Exception("无法获取主框架");
                }
                
                Console.WriteLine($"执行JavaScript代码: {jsCode}");
                
                var callback = new FBroSharpJsCallbackSyn();
                frame.ExecuteJavaScriptToHasReturn(jsCode, default, default, callback);
                
                if (callback.help?.IsValid == true)
                {
                    Console.WriteLine("等待JavaScript执行结果...");
                    await Task.Run(() => callback.help.WaitEvent(10000));
                    if (callback.help.HavStringData())
                    {
                        string result = callback.help.GetStringData();
                        Console.WriteLine($"JavaScript执行结果: {result}");
                        callback.help.ClearData();
                        return result;
                    }
                    else
                    {
                        Console.WriteLine("JavaScript执行没有返回字符串数据");
                    }
                }
                else
                {
                    Console.WriteLine("JavaScript回调无效");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"执行JavaScript时出错: {ex.Message}");
                throw;
            }
            
            return null;
        }

        /// <summary>
        /// JavaScript 回调类
        /// </summary>
        public class FBroSharpJsCallbackSyn : FBroSharpJsCallback
        {
            // 同步辅助类 - 用于线程同步等待
            public FBroSharpSynHelp help;
            
            public FBroSharpJsCallbackSyn()
            {
                // 初始化help类
                help = new FBroSharpSynHelp();
            }

            /// <summary>
            /// JavaScript 执行完成后的回调方法
            /// 根据返回类型保存数据到 help 中
            /// </summary>
            public override void Callback(FBroSharpJSRequestType type, IFBroSharpValue data, string error)
            {
                // 将返回的数据保存在help中
                if (help != null && help.IsValid)
                {
                    switch (type)
                    {
                        case FBroSharpJSRequestType.VALUE_ISVALID:
                            // 无效
                            help.SetStringData(error);
                            break;
                            
                        case FBroSharpJSRequestType.VALUE_NULL:
                            // 空值
                            help.SetStringData("无值");
                            break;
                            
                        case FBroSharpJSRequestType.VALUE_INT:
                            // 整数值
                            help.SetIntData(data.GetInt());
                            break;
                            
                        case FBroSharpJSRequestType.VALUE_STRING:
                            // 文本值
                            help.SetStringData(data.GetString());
                            break;
                            
                        case FBroSharpJSRequestType.VALUE_BOOL:
                            // 逻辑值
                            help.SetBoolData(data.GetBool());
                            break;
                            
                        case FBroSharpJSRequestType.VALUE_DOUBLE:
                            // 双精度小数值
                            help.SetDoubleData(data.GetDouble());
                            break;
                            
                        case FBroSharpJSRequestType.VALUE_DATA_STRING:
                            // 时间文本值
                            help.SetStringData(data.GetString());
                            break;
                            
                        case FBroSharpJSRequestType.VALUE_ARRAY:
                            // 数组值
                            help.SetStringData(data.GetString());
                            break;
                            
                        case FBroSharpJSRequestType.VALUE_ARRAY_BUFFER:
                            // 数组缓存值
                            help.SetStringData(data.GetString());
                            break;
                            
                        case FBroSharpJSRequestType.VALUE_FUNCTION:
                            // 方法值
                            help.SetStringData(data.GetString());
                            break;
                            
                        case FBroSharpJSRequestType.VALUE_OBJECT:
                            // 对象值（JSON）
                            help.SetStringData(data.GetString());
                            break;
                    }
                    
                    // 停止等待，唤醒主线程
                    help.StopEvent();
                }
            }
        }

        /// <summary>
        /// 读取 Excel 文件
        /// </summary>
        private DataTable ReadExcelFile(string filePath)
        {
            var dataTable = new DataTable();
            
            using (var package = new ExcelPackage(new FileInfo(filePath)))
            {
                var worksheet = package.Workbook.Worksheets[0]; // 读取第一个工作表
                
                // 读取表头
                for (int col = 1; col <= worksheet.Dimension.End.Column; col++)
                {
                    var headerCell = worksheet.Cells[1, col];
                    dataTable.Columns.Add(headerCell.Text);
                }
                
                // 读取数据行
                for (int row = 2; row <= worksheet.Dimension.End.Row; row++)
                {
                    var dataRow = dataTable.NewRow();
                    for (int col = 1; col <= worksheet.Dimension.End.Column; col++)
                    {
                        dataRow[col - 1] = worksheet.Cells[row, col].Text;
                    }
                    dataTable.Rows.Add(dataRow);
                }
            }
            
            return dataTable;
        }

        /// <summary>
        /// 读取 CSV 文件
        /// </summary>
        private DataTable ReadCsvFile(string filePath)
        {
            var dataTable = new DataTable();
            var lines = File.ReadAllLines(filePath);
            
            if (lines.Length == 0)
                return dataTable;
            
            // 读取表头
            var headers = lines[0].Split(',');
            foreach (var header in headers)
            {
                dataTable.Columns.Add(header.Trim());
            }
            
            // 读取数据行
            for (int i = 1; i < lines.Length; i++)
            {
                var values = lines[i].Split(',');
                var dataRow = dataTable.NewRow();
                for (int j = 0; j < Math.Min(values.Length, headers.Length); j++)
                {
                    dataRow[j] = values[j].Trim();
                }
                dataTable.Rows.Add(dataRow);
            }
            
            return dataTable;
        }

        /// <summary>
        /// 添加一个简单的测试按钮来逐步验证表单填写
        /// </summary>
        private async void btnTestStepByStep_Click(object sender, EventArgs e)
        {
            if (browser == null || !browser.IsValid)
            {
                browser = FBroSharpBrowserListControl.GetBrowserFromFlag(BROWSER_USER_FLAG);
                if (browser == null || !browser.IsValid)
                {
                    MessageBox.Show("请先初始化浏览器", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
            }
            
            try
            {
                // 步骤1: 填写客户姓名
                MessageBox.Show("步骤1: 填写客户姓名", "测试", MessageBoxButtons.OK, MessageBoxIcon.Information);
                var result1 = await FillInputAsync(browser, "input[name='custname']", "测试用户");
                MessageBox.Show($"填写结果: {result1}", "步骤1结果", MessageBoxButtons.OK, MessageBoxIcon.Information);
                
                // 等待并检查结果
                await Task.Delay(1000);
                
                // 步骤2: 填写电话
                MessageBox.Show("步骤2: 填写电话", "测试", MessageBoxButtons.OK, MessageBoxIcon.Information);
                var result2 = await FillInputAsync(browser, "input[name='custtel']", "13800138000");
                MessageBox.Show($"填写结果: {result2}", "步骤2结果", MessageBoxButtons.OK, MessageBoxIcon.Information);
                
                // 等待并检查结果
                await Task.Delay(1000);
                
                // 步骤3: 选择披萨尺寸
                MessageBox.Show("步骤3: 选择披萨尺寸", "测试", MessageBoxButtons.OK, MessageBoxIcon.Information);
                var result3 = await CheckCheckboxAsync(browser, "input[name='size'][value='large']", true);
                MessageBox.Show($"选择结果: {result3}", "步骤3结果", MessageBoxButtons.OK, MessageBoxIcon.Information);
                
                MessageBox.Show("逐步测试完成！", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"测试失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private async void Form1_Load(object sender, EventArgs e)
        {
            await CreateBrowserAsync();
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            if (browser != null && browser.IsValid)
            {
                browser.CloseBrowser(false);
            }
            //FBroSharpControl.Shutdown(false);
            base.OnFormClosing(e);
        }
    }
}